iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0

TL;DR

這是「Modern Blog 30 天」系列第 8 篇文章,上一篇我們實作了 Markdown 格式的文章內頁,這篇我們會擴充它,讓他支援 MDX 格式,能在 Markdown 內插入任何 React 元件,提升文章內容靈活度!

結果截圖如下:

MDX post result

這篇修改的程式碼如下:

https://github.com/Kamigami55/nextjs-tailwind-contentlayer-blog-starter/compare/day07-post-apge-bare-bone...day08-mdx-support

我的個人網站裡也有此系列的好讀版,程式碼更易讀、也支援深色模式和側邊目錄,歡迎前往閱讀!


讓 Contentlayer 支援 MDX 格式

修改 contentlayer.config.ts 檔案

修改 filePathPattern 檔名,以及新增 contentType:

import { defineDocumentType, makeSource } from './src/lib/contentLayerAdapter';

export const Post = defineDocumentType(() => ({
  name: 'Post',
  // 更新 filePathPattern,從 *.md 改成 *.mdx,
  filePathPattern: `content/posts/**/*.mdx`,
  // 並新增下面這行 contentType
  contentType: 'mdx',
  fields: {
    title: {
      type: 'string',
      required: true,
    },
    description: {
      type: 'string',
      required: true,
    },
    slug: {
      type: 'string',
      required: true,
    },
    date: {
      type: 'date',
      required: true,
    },
  },
  computedFields: {
    path: {
      type: 'string',
      resolve: (post) => `/posts/${post.slug}`,
    },
  },
}));

export default makeSource({
  contentDirPath: 'content',
  documentTypes: [Post],
});

修改文章內頁的 src/pages/posts/[slug].tsx 檔案

替換掉 render html 的 div,改成 render <MDXContent />

import { format, parseISO } from 'date-fns';
import type { GetStaticPaths, GetStaticProps, NextPage } from 'next';
import Head from 'next/head';
// 新增下面這行
import { useMDXComponent } from 'next-contentlayer/hooks';

import { allPosts, Post } from '@/lib/contentLayerAdapter';
import styles from '@/styles/Home.module.css';

export const getStaticPaths: GetStaticPaths = () => {
  const paths = allPosts.map((post) => post.path);
  return {
    paths,
    fallback: false,
  };
};

export const getStaticProps: GetStaticProps<Props> = ({ params }) => {
  const post = allPosts.find((post) => post.slug === params?.slug);
  if (!post) {
    return {
      notFound: true,
    };
  }
  return {
    props: {
      post,
    },
  };
};

type Props = {
  post: Post;
};

const PostPage: NextPage<Props> = ({ post }) => {
  // 以及新增下面這行
  const MDXContent = useMDXComponent(post.body.code);

  return (
    <div className={styles.container}>
      <Head>
        <title>{post.title}</title>
        <meta name="description" content={post.description} />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>{post.title}</h1>

        <time dateTime={post.date}>
          {format(parseISO(post.date), 'LLLL d, yyyy')}
        </time>

        // 替換掉 render html 的 div,改為 <MDXContent />
        // <div dangerouslySetInnerHTML={{ __html: post.body.html }} />
        <MDXContent />
      </main>
    </div>
  );
};

export default PostPage;

將所有文章副檔名由 .md 改成 .mdx

將所有 content/posts/ 底下的文章副檔名改成 .mdx

如此一來就完成 MDX 格式支援了!

新增任意 React 元件,並插入 MDX 文章內

接著讓我們來測試將 React 元件放進 MDX 文章的 Markdown 內容之間。

新增 src/components/CustomInput.tsx

const CustomInput = () => {
  return (
    <div>
      <p>Hello</p>
      <input type="text" />
    </div>
  );
};

export default CustomInput;

修改 content/posts/20220831-markdown-demo.mdx

插入剛剛的 CustomInput 元件:

---
title: Markdown demo
description: This is a demo of Markdown
slug: markdown-demo
date: 2022-08-31
type: Post
---

import CustomInput from '../../src/components/CustomInput';

## H2 title

### H3 title

Some content with [link](https://www.google.com)

<CustomInput />

成果

完成了!使用 pnpm dev 並進入有客製化 MDX 元件的文章,就會看到 MDX 元件顯示在畫面上了。

網址會長得像這樣:

http://localhost:3000/posts/markdown-demo

截圖如下,可以看到多了一個用 React 做成的文字輸入框:

MDX post result

這篇修改的程式碼如下:

https://github.com/Kamigami55/nextjs-tailwind-contentlayer-blog-starter/compare/day07-post-apge-bare-bone...day08-mdx-support

下一篇

恭喜你!目前為止我們也能用 MDX 格式撰寫文章了!能在任意地方插入任何 React 做得出來的客製化元件,讓文章內容的靈活度更好!

但目前整個 Blog 還挺醜的,接下來讓我們著手開始美化樣式吧!

我們會使用到 Tailwind CSS 這套最近很熱門的 CSS Framework,下一篇讓我們來安裝並使用它!


上一篇
文章內頁功能實作,渲染 Markdown 文章內容 - Modern Next.js Blog 系列 #07
下一篇
安裝 Tailwind CSS 和相關 ESLint、Prettier 設定 - Modern Next.js Blog 系列 #09
系列文
從零開始打造炫砲個人部落格,使用 Next.js、ContentLayer、i18next 等現代技術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言